package com.ima;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.Shader;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.LinearLayout;
import com.dev.GUI;
import com.dev.IconView;
import com.dev.MainActivity;
import com.log;
import java.util.concurrent.TimeoutException;

import static com.ima.ImageManipulationPage.*;

class CanvasView extends View {
	public Bitmap image;
	public Bitmap imageMask;
	//LayerTab baseLayer;
	Layer currentLayer;
	Paint bitmapPaint=new Paint();
	Point crosswire;
	Paint wirePaint;

	ImageManipulationPage imp;
	MainActivity ma;
	RectSelection rectSelection;
	EllipseSelection ellip;
	Path path;
	byte[] selected;
	int imageW;
	int imageH;
	int imageWMax;
	int imageWMin;
	int scrollXMax;
	int scrollYMax;
	int deviation;
	boolean growAngle;
	CanvasView(ImageManipulationPage imp){
		super(imp.ma);
		this.ma=imp.ma;
		this.imp=imp;
		bitmapPaint.setDither(false);
		bitmapPaint.setAntiAlias(false);
		bitmapPaint.setFilterBitmap(false);
		scaleRate=1/((int)(80*ma.dp));
		wirePaint=new Paint();
		wirePaint.setColor(0xffff0000);
	}
	public void atImageChange(){
		imp.canSave=true;
		imp.canRefresh=true;
		ImageFrame ii=new ImageFrame(image);
		imp.undoable.push(ii);
		ma.gui.ivUndo.setColorFilter(null);
		ma.gui.ivUndo.invalidate();
		imp.redoable.clear();
		ma.gui.ivRedo.setColorFilter(IconView.unable);
		ma.gui.ivRedo.invalidate();
		ma.gui.ivSave.setColorFilter(null);
		ma.gui.ivSave.invalidate();
		ma.gui.ivRefresh.setColorFilter(null);
		ma.gui.ivRefresh.invalidate();
	}

	@Override
	protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
		super.onLayout(changed, left, top, right, bottom);
	}
	Point touchDown=new Point();
	Point touchDownRaw=new Point();
	Point finger2Down=new Point();
	volatile boolean fingerMoved;
	volatile boolean fingerPressed;
	volatile boolean longClicked;
	boolean scaled;
	int scrollXSaved;
	int scrollYSaved;
	int moveOrientation;
	int imageWSaved;
	int imageHSaved;
	float distanceSaved;
	final int fingerMovedLimit=7;
	float scaleSaved;
	float scaleRate;
	int longClickLim=240;
	class WaitLongClick extends Thread {
		@Override
		public void run() {
			super.run();
			try{
				sleep(longClickLim);
				longClicked=true;
				if(imp.ivMouse.isSelected()){
					atLongClick(cursorX,cursorY);
				}else{
					int xx=touchDown.x;
					int yy=touchDown.y;
					atLongClick(xx,yy);
				}

			}catch(InterruptedException e){}
		}
		void atLongClick(final int xx,final int yy){
			if(currentLayer==null){
				int sx=getScrollX();
				int sy=getScrollY();
				int actionx=sx+xx;
				int actiony=sy+yy;
				final Point px=calculClicked(actionx,actiony);

				if(rectSelection!=null){
					if(px!=null){
						post(new Runnable(){
								@Override 
								public void run(){
									crosswire=new Point(px.x,px.y);invalidate();
									if(px.x>=rectSelection.left&&px.x<rectSelection.right&&px.y>=rectSelection.top&&px.y<rectSelection.right){
										if(queryForSelection==null)queryForSelection=new QueryForSelection();
										Rect rect=new Rect();
										CanvasView.this.getGlobalVisibleRect(rect);
										queryForSelection.wlp.x=xx+rect.left;
										queryForSelection.wlp.y=yy+rect.top;
										queryForSelection.show(2);
									}else{
										if(queryForLayer==null)queryForLayer=new QueryForLayer();
										Rect rect=new Rect();
										CanvasView.this.getGlobalVisibleRect(rect);
										queryForLayer.wlp.x=xx+rect.left;
										queryForLayer.wlp.y=yy+rect.top;
										queryForLayer.show();
									}
								}
							});
					}
				}else if(ellip!=null){
					if(px==null)return;
					post(new Runnable(){
							@Override 
							public void run(){
								crosswire=new Point(px.x,px.y);invalidate();
								if(px.x>=ellip.left&&px.x<ellip.right&&px.y>=ellip.top&&px.y<ellip.bottom){
									if(queryForSelection==null)queryForSelection=new QueryForSelection();
									Rect rect=new Rect();
									CanvasView.this.getGlobalVisibleRect(rect);
									queryForSelection.wlp.x=xx+rect.left;
									queryForSelection.wlp.y=yy+rect.top;
									queryForSelection.show(3);
								}else{
									if(queryForLayer==null)queryForLayer=new QueryForLayer();
									Rect rect=new Rect();
									CanvasView.this.getGlobalVisibleRect(rect);
									queryForLayer.wlp.x=xx+rect.left;
									queryForLayer.wlp.y=yy+rect.top;
									queryForLayer.show();
								}
							}
						});
				}else if(selected!=null){
					if(px!=null){
						post(new Runnable(){
								@Override 
								public void run(){
									crosswire=new Point(px.x,px.y);invalidate();
									byte n=selected[px.x+iw*px.y];
									if(n!=0){
										if(queryForSelection==null)queryForSelection=new QueryForSelection();
										Rect rect=new Rect();
										CanvasView.this.getGlobalVisibleRect(rect);
										queryForSelection.wlp.x=xx+rect.left;
										queryForSelection.wlp.y=yy+rect.top;
										queryForSelection.show(1);
									}else{
										if(queryForLayer==null)queryForLayer=new QueryForLayer();
										Rect rect=new Rect();
										CanvasView.this.getGlobalVisibleRect(rect);
										queryForLayer.wlp.x=xx+rect.left;
										queryForLayer.wlp.y=yy+rect.top;
										queryForLayer.show();
									}
								}
							});
					}

				}else{
					if(px==null)return;
					post(new Runnable(){
							@Override 
							public void run(){
								crosswire=new Point(px.x,px.y);invalidate();
								if(queryForLayer==null)queryForLayer=new QueryForLayer();
								Rect rect=new Rect();
								CanvasView.this.getGlobalVisibleRect(rect);
								queryForLayer.wlp.x=xx+rect.left;
								queryForLayer.wlp.y=yy+rect.top;
								queryForLayer.show();
							}
						});
				}
			}
		}
	}
	WaitLongClick wlc;
	QueryForSelection queryForSelection;
	class QueryForSelection extends LinearLayout implements OnClickListener{
		WindowManager.LayoutParams wlp=new WindowManager.LayoutParams();
		GUI.Item itClear;
		int intend;
		QueryForSelection(){
			super(ma);
			setOrientation(VERTICAL);
			setBackground(new GUI.BorderDrawable());
			wlp.gravity=Gravity.LEFT|Gravity.TOP;
			wlp.flags=wlp.FLAG_LAYOUT_IN_SCREEN;
			itClear=new GUI.Item(ma);
			itClear.setText("放弃选区");
			itClear.setOnClickListener(this);
			LayoutParams itlp=new LayoutParams(-1,dialogHorItemHeight);
			addView(itClear,itlp);
		}
		void show(int intend){
			this.intend=intend;
			wlp.width=ma.wp/2;
			wlp.height=-2;
			ma.wm.addView(this,wlp);
		}
		@Override
		public void onClick(View view) {
			if(view==itClear){
				if(intend==1){
					selected=null;
					Canvas canvas=new Canvas(imageMask);
					canvas.drawColor(0,PorterDuff.Mode.SRC);
					CanvasView.this.invalidate();
					ma.wm.removeView(this);
				}else if(intend==2){
					rectSelection=null;
					CanvasView.this.invalidate();
					ma.wm.removeView(this);
				}

			}
		}
		Point touchDown=new Point();
		@Override
		public boolean onTouchEvent(MotionEvent event){
			int x=(int)event.getX();
			int y=(int)event.getY();
			switch(event.getAction()){
				case MotionEvent.ACTION_DOWN:
					touchDown.x=x;
					touchDown.y=y;
					break;
				case MotionEvent.ACTION_UP:
					Rect visible=new Rect();
					getGlobalVisibleRect(visible);
					int[] is=new int[2];
					getLocationOnScreen(is);
					if(touchDown.x>=visible.right||touchDown.x<visible.right||touchDown.y>=visible.bottom||touchDown.y<visible.top){
						ma.wm.removeView(this);
					}
			}
			super.onTouchEvent(event);
			return true;
		}
	}
	QueryForLayer queryForLayer;
	int cursorXSaved;
	int cursorYSaved;
	boolean doubleClicked;
	long downTime=System.currentTimeMillis();
	int scrollYMin;
	int scrollXMin;
	int scaleCenterX;
	int scaleCenterY;
	Point partSaved=new Point();
	Point pxSaved=new Point();
	byte partPressed;
	RectSelection rectSaved;
	EllipseSelection ellipSaved;
	int ex,ey;
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		ex=(int)event.getX();
		ey=(int)event.getY();
		int sx=getScrollX();
		int sy=getScrollY();
		int iw=image.getWidth();
		int ih=image.getHeight();
		int imageH=ih*imageW/iw;
		float scale=imageW/(float)iw;
		switch(event.getActionMasked()){
			case MotionEvent.ACTION_DOWN:
				touchDown.x=ex;
				touchDown.y=ey;
				touchDownRaw.x=(int)event.getRawX();
				touchDownRaw.y=(int)event.getRawY();
				fingerMoved=false;
				fingerPressed=true;
				longClicked=false;
				imageWSaved=imageW;
				imageHSaved=imageH;
				scaled=false;
				scrollXSaved=getScrollX();
				scrollYSaved=getScrollY();
				if(imp.ivMouse.isSelected()){
					cursorXSaved=cursorX;
					cursorYSaved=cursorY;
					int actionx=cursorX+sx;
					int actiony=cursorY+sy;
					if(System.currentTimeMillis()-downTime<180){
						doubleClicked=true;
						int ix=iw*actionx/imageW;
						int iy=ih*actiony/imageH;
						if(imp.ivNow==imp.ivRectSelect){
							if(rectSelection==null){
								partPressed=0;
							}else{
								int gl=(int)(rectSelection.left*scale);
								int gt=(int)(rectSelection.top*scale);
								int gr=(int)(rectSelection.right*scale);
								int gb=(int)(rectSelection.bottom*scale);
								int ll=gr-handleRadius;
								int tt=gb-handleRadius;
								int rr=gr+handleRadius;
								int bb=gb+handleRadius;
								pxSaved.x=ix;
								pxSaved.y=iy;
								if(actionx>=ll&&actionx<rr&&actiony>=tt&&actiony<bb){
									partPressed=4;
									partSaved.x=rectSelection.right;
									partSaved.y=rectSelection.bottom;
								}else{
									ll=gl-handleRadius;
									tt=gt-handleRadius;
									rr=gl+handleRadius;
									bb=gt+handleRadius;
									if(actionx>=ll&&actionx<rr&&actiony>=tt&&actiony<bb){
										partPressed=1;
										partSaved.x=rectSelection.left;
										partSaved.y=rectSelection.top;
									}else{
										int cx=(gr-gl)/2+gl;
										int cy=(gb-gt)/2+gt;
										ll=cx-handleRadius;
										tt=cy-handleRadius;
										rr=cx+handleRadius;
										bb=cy+handleRadius;
										if(actionx>=ll&&actionx<rr&&actiony>=tt&&actiony<bb){
											partPressed=5;
											rectSaved=rectSelection.copy();
										}else{
											partPressed=0;
										}
									}
								}
							}
						}else if(imp.ivNow==imp.ivEllipseSelect){
							if(ellip==null){
								partPressed=0;
							}else{
								int gl=(int)(ellip.left*scale);
								int gt=(int)(ellip.top*scale);
								int gr=(int)(ellip.right*scale);
								int gb=(int)(ellip.bottom*scale);
								int ll=gr-handleRadius;
								int tt=gb-handleRadius;
								int rr=gr+handleRadius;
								int bb=gb+handleRadius;
								actionx=cursorX+sx;
								actiony=cursorY+sy;
								int px=iw*actionx/imageW;
								int py=ih*actiony/imageH;
								pxSaved.x=px;
								pxSaved.y=py;
								if(actionx>=ll&&actionx<rr&&actiony>=tt&&actiony<bb){
									partPressed=4;
									partSaved.x=ellip.right;
									partSaved.y=ellip.bottom;
								}else{
									ll=gl-handleRadius;
									tt=gt-handleRadius;
									rr=gl+handleRadius;
									bb=gt+handleRadius;
									if(actionx>=ll&&actionx<rr&&actiony>=tt&&actiony<bb){
										partPressed=1;
										partSaved.x=ellip.left;
										partSaved.y=ellip.top;
									}else{
										int cx=(gr-gl)/2+gl;
										int cy=(gb-gt)/2+gt;
										ll=cx-handleRadius;
										tt=cy-handleRadius;
										rr=cx+handleRadius;
										bb=cy+handleRadius;
										if(actionx>=ll&&actionx<rr&&actiony>=tt&&actiony<bb){
											partPressed=5;
											ellipSaved=ellip.copy();
										}else{
											partPressed=0;
										}
									}
								}
							}
						}
					}else{//not in the drag
						partPressed=0;
						doubleClicked=false;
						if(wlc==null){
							wlc=new WaitLongClick();
							wlc.start();
						}else{
							wlc.interrupt();
							wlc=new WaitLongClick();
							wlc.start();
						}
					}
					downTime=System.currentTimeMillis();
				}else{//ivMouse.isSelected()==false
					int actionx=ex+sx;
					int actiony=ey+sy;
					int ix=iw*actionx/imageW;
					int iy=ih*actiony/imageH;
					if(wlc==null){
						wlc=new WaitLongClick();
						wlc.start();
					}else{
						wlc.interrupt();
						wlc=new WaitLongClick();
						wlc.start();
					}
					if(imp.ivNow==imp.ivRectSelect){
						if(rectSelection==null){
							partPressed=0;
						}else{
							int gl=(int)(rectSelection.left*scale);
							int gt=(int)(rectSelection.top*scale);
							int gr=(int)(rectSelection.right*scale);
							int gb=(int)(rectSelection.bottom*scale);
							int ll=gr-handleRadius;
							int tt=gb-handleRadius;
							int rr=gr+handleRadius;
							int bb=gb+handleRadius;
							pxSaved.x=ix;
							pxSaved.y=iy;
							if(actionx>=ll&&actionx<rr&&actiony>=tt&&actiony<bb){
								partPressed=4;
								partSaved.x=rectSelection.right;
								partSaved.y=rectSelection.bottom;
							}else{
								ll=gl-handleRadius;
								tt=gt-handleRadius;
								rr=gl+handleRadius;
								bb=gt+handleRadius;
								if(actionx>=ll&&actionx<rr&&actiony>=tt&&actiony<bb){
									partPressed=1;
									partSaved.x=rectSelection.left;
									partSaved.y=rectSelection.top;
								}else{
									int cx=(gr-gl)/2+gl;
									int cy=(gb-gt)/2+gt;
									ll=cx-handleRadius;
									tt=cy-handleRadius;
									rr=cx+handleRadius;
									bb=cy+handleRadius;
									if(actionx>=ll&&actionx<rr&&actiony>=tt&&actiony<bb){
										partPressed=5;
										rectSaved=rectSelection.copy();
									}else{
										partPressed=0;
									}
								}
							}
						}
					}else if(imp.ivNow==imp.ivEllipseSelect){
						if(ellip==null){
							partPressed=0;
						}else{
							int gl=(int)(ellip.left*scale);
							int gt=(int)(ellip.top*scale);
							int gr=(int)(ellip.right*scale);
							int gb=(int)(ellip.bottom*scale);
							int ll=gr-handleRadius;
							int tt=gb-handleRadius;
							int rr=gr+handleRadius;
							int bb=gb+handleRadius;
							pxSaved.x=ix;
							pxSaved.y=iy;
							if(actionx>=ll&&actionx<rr&&actiony>=tt&&actiony<bb){
								partPressed=4;
								partSaved.x=ellip.right;
								partSaved.y=ellip.bottom;
							}else{
								ll=gl-handleRadius;
								tt=gt-handleRadius;
								rr=gl+handleRadius;
								bb=gt+handleRadius;
								if(actionx>=ll&&actionx<rr&&actiony>=tt&&actiony<bb){
									partPressed=1;
									partSaved.x=ellip.left;
									partSaved.y=ellip.top;
								}else{
									int cx=(gr-gl)/2+gl;
									int cy=(gb-gt)/2+gt;
									ll=cx-handleRadius;
									tt=cy-handleRadius;
									rr=cx+handleRadius;
									bb=cy+handleRadius;
									if(actionx>=ll&&actionx<rr&&actiony>=tt&&actiony<bb){
										partPressed=5;
										ellipSaved=ellip.copy();
									}else{
										partPressed=0;
									}
								}
							}
						}
					}else if(imp.ivNow==imp.ivPath){
						if(path==null){
							path=new Path();
							path.moveTo(ix,iy);
						}else{

						}
					}
				}
				break;
			case MotionEvent.ACTION_POINTER_DOWN:
				finger2Down.x=ex;
				finger2Down.y=ey;
				/*scrollXSaved=getScrollX();
				scrollYSaved=getScrollY();*/
				if(event.getPointerCount()==2){
					int xn=(int)event.getX(1);
					int yn=(int)event.getY(1);
					int a=Math.abs(ex-xn);
					int b=Math.abs(ey-yn);
					scaleCenterX=(ex+xn)/2;
					scaleCenterY=(ey+yn)/2;
					distanceSaved=(float)Math.sqrt(a*a+b*b);
				}
				break;
			case MotionEvent.ACTION_POINTER_UP:
				if(event.getPointerCount()>1){
					int a=(int)Math.abs(event.getX(0)-event.getX(1));
					int b=(int)Math.abs(event.getY(0)-event.getY(1));
					distanceSaved=(float)Math.sqrt(a*a+b*b);
				}
				break;
			case MotionEvent.ACTION_MOVE:
				if(event.getPointerCount()==1&&!scaled){
					int dx=ex-touchDown.x;
					int dy=ey-touchDown.y;
					if(fingerMoved){
						int vw=getWidth();
						int vh=getHeight();
						int actionx,actiony;
						if(imp.ivMouse.isSelected()){
							actionx=cursorX+sx;
							actiony=cursorY+sy;
							int cursorXWill=cursorXSaved+dx;
							int cursorYWill=cursorYSaved+dy;
							int ix=iw*actionx/imageW;
							int iy=ih*actiony/imageH;
							if(doubleClicked){
								if(imp.ivNow==imp.ivRectSelect){
									if(rectSelection==null){
										rectSelection=new RectSelection();
										rectSelection.left=iw*(touchDown.x+sx)/imageW;
										rectSelection.top=ih*(touchDown.y+sy)/imageH;
										rectSelection.right=ix;
										rectSelection.bottom=iy;
										partPressed=4;
										partSaved.x=rectSelection.right;
										partSaved.y=rectSelection.bottom;
										pxSaved.x=ix;
										pxSaved.y=iy;
									}else if(partPressed==1){
										rectSelection.left=partSaved.x+(ix-pxSaved.x);
										rectSelection.top=partSaved.y+(iy-pxSaved.y);
										imp.status.setText("左="+rectSelection.left+",上="+rectSelection.top+",右="+rectSelection.right+",下="+rectSelection.bottom+",宽="+(rectSelection.right-rectSelection.left)+",高"+(rectSelection.bottom-rectSelection.top));
										invalidate();
									}else if(partPressed==4){
										rectSelection.right=partSaved.x+(ix-pxSaved.x);
										rectSelection.bottom=partSaved.y+(iy-pxSaved.y);
										imp.status.setText("左="+rectSelection.left+",上="+rectSelection.top+",右="+rectSelection.right+",下="+rectSelection.bottom+",宽="+(rectSelection.right-rectSelection.left)+",高"+(rectSelection.bottom-rectSelection.top));
										invalidate();
									}else if(partPressed==5){
										int deltax=ix-pxSaved.x;
										int deltay=iy-pxSaved.y;
										rectSelection.left=rectSaved.left+deltax;
										rectSelection.top=rectSaved.top+deltay;
										rectSelection.right=rectSaved.right+deltax;
										rectSelection.bottom=rectSaved.bottom+deltay;
										imp.status.setText("左="+rectSelection.left+",上="+rectSelection.top+",右="+rectSelection.right+",下="+rectSelection.bottom+",宽="+(rectSelection.right-rectSelection.left)+",高"+(rectSelection.bottom-rectSelection.top));
										invalidate();
									}else{
										atFingerScrolling(cursorX-cursorXSaved,cursorY-cursorYSaved);
									}
								}else if(imp.ivNow==imp.ivEllipseSelect){
									if(ellip==null){
										ellip=new EllipseSelection();
										ellip.left=iw*(touchDown.x+sx)/imageW;
										ellip.top=ih*(touchDown.y+sy)/imageH;
										ellip.right=ix;
										ellip.bottom=iy;
										partPressed=4;
										partSaved.x=ellip.right;
										partSaved.y=ellip.bottom;
										pxSaved.x=ix;
										pxSaved.y=iy;
									}else if(partPressed==1){
										ellip.left=partSaved.x+(ix-pxSaved.x);
										ellip.top=partSaved.y+(iy-pxSaved.y);
										imp.status.setText("左="+ellip.left+",上="+ellip.top+",右="+ellip.right+",下="+ellip.bottom+",宽="+(ellip.right-ellip.left)+",高"+(ellip.bottom-ellip.top));
										invalidate();
									}else if(partPressed==4){
										ellip.right=partSaved.x+(ix-pxSaved.x);
										ellip.bottom=partSaved.y+(iy-pxSaved.y);
										imp.status.setText("左="+ellip.left+",上="+ellip.top+",右="+ellip.right+",下="+ellip.bottom+",宽="+(ellip.right-ellip.left)+",高"+(ellip.bottom-ellip.top));
										invalidate();
									}else if(partPressed==5){
										int deltax=ix-pxSaved.x;
										int deltay=iy-pxSaved.y;
										ellip.left=ellipSaved.left+deltax;
										ellip.top=ellipSaved.top+deltay;
										ellip.right=ellipSaved.right+deltax;
										ellip.bottom=ellipSaved.bottom+deltay;
										imp.status.setText("左="+ellip.left+",上="+ellip.top+",右="+ellip.right+",下="+ellip.bottom+",宽="+(ellip.right-ellip.left)+",高"+(ellip.bottom-ellip.top));
										invalidate();
									}else{
										atFingerScrolling(cursorX-cursorXSaved,cursorY-cursorYSaved);
									}
								}else{
									atFingerScrolling(cursorX-cursorXSaved,cursorY-cursorYSaved);
								}
							}
							if(cursorXWill<=vw){
								if(cursorXWill>=0){
									cursorX=cursorXWill;
									if(cursorYWill<=vh){
										if(cursorYWill>=0){
											cursorY=cursorYWill;
											invalidate();
										}else{
											cursorY=0;
											invalidate();
										}
									}else{
										cursorY=vh;
										invalidate();
									}
								}else{
									cursorX=0;
									if(cursorYWill<=vh){
										if(cursorYWill>=0){
											cursorY=cursorYWill;
											invalidate();
										}else{
											cursorY=0;
											invalidate();
										}
									}else{
										cursorY=vh;
										invalidate();
									}
								}
							}else{
								cursorX=vw;
								if(cursorYWill<=vh){
									if(cursorYWill>=0){
										cursorY=cursorYWill;
										invalidate();
									}else{
										cursorY=0;
										invalidate();
									}
								}else{
									cursorY=vh;
									invalidate();
								}
							}
							Point point=calculClicked(cursorX+getScrollX(),cursorY+getScrollY());
							if(point!=null){
								imp.status.setText("x="+point.x+",y="+point.y);
							}
						}else{//ivMouse.isSelected()==false
							actionx=ex+sx;
							actiony=ey+sy;
							int ix=iw*actionx/imageW;
							int iy=ih*actiony/imageH;
							if(imp.ivNow==imp.ivRectSelect){
								if(rectSelection==null){
									rectSelection=new RectSelection();
									rectSelection.left=iw*(touchDown.x+sx)/imageW;
									rectSelection.top=ih*(touchDown.y+sy)/imageH;
									rectSelection.right=ix;
									rectSelection.bottom=iy;
									partPressed=4;
									partSaved.x=rectSelection.right;
									partSaved.y=rectSelection.bottom;
									pxSaved.x=ix;
									pxSaved.y=iy;
								}else if(partPressed==1){
									rectSelection.left=partSaved.x+(ix-pxSaved.x);
									rectSelection.top=partSaved.y+(iy-pxSaved.y);
									imp.status.setText("左="+rectSelection.left+",上="+rectSelection.top+",右="+rectSelection.right+",下="+rectSelection.bottom+",宽="+(rectSelection.right-rectSelection.left)+",高"+(rectSelection.bottom-rectSelection.top));
									invalidate();
								}else if(partPressed==4){
									rectSelection.right=partSaved.x+(ix-pxSaved.x);
									rectSelection.bottom=partSaved.y+(iy-pxSaved.y);
									imp.status.setText("左="+rectSelection.left+",上="+rectSelection.top+",右="+rectSelection.right+",下="+rectSelection.bottom+",宽="+(rectSelection.right-rectSelection.left)+",高"+(rectSelection.bottom-rectSelection.top));
									invalidate();
								}else if(partPressed==5){
									int deltax=ix-pxSaved.x;
									int deltay=iy-pxSaved.y;
									rectSelection.left=rectSaved.left+deltax;
									rectSelection.top=rectSaved.top+deltay;
									rectSelection.right=rectSaved.right+deltax;
									rectSelection.bottom=rectSaved.bottom+deltay;
									imp.status.setText("左="+rectSelection.left+",上="+rectSelection.top+",右="+rectSelection.right+",下="+rectSelection.bottom+",宽="+(rectSelection.right-rectSelection.left)+",高"+(rectSelection.bottom-rectSelection.top));
									invalidate();
								}else{
									atFingerScrolling(dx,dy);
								}
							}else if(imp.ivNow==imp.ivEllipseSelect){
								if(ellip==null){
									ellip=new EllipseSelection();
									ellip.left=iw*(touchDown.x+sx)/imageW;
									ellip.top=ih*(touchDown.y+sy)/imageH;
									ellip.right=ix;
									ellip.bottom=iy;
									partPressed=4;
									partSaved.x=ellip.right;
									partSaved.y=ellip.bottom;
									pxSaved.x=ix;
									pxSaved.y=iy;
								}else if(partPressed==1){
									ellip.left=partSaved.x+(ix-pxSaved.x);
									ellip.top=partSaved.y+(iy-pxSaved.y);
									imp.status.setText("左="+ellip.left+",上="+ellip.top+",右="+ellip.right+",下="+ellip.bottom+",宽="+(ellip.right-ellip.left)+",高"+(ellip.bottom-ellip.top));
									invalidate();
								}else if(partPressed==4){
									ellip.right=partSaved.x+(ix-pxSaved.x);
									ellip.bottom=partSaved.y+(iy-pxSaved.y);
									imp.status.setText("左="+ellip.left+",上="+ellip.top+",右="+ellip.right+",下="+ellip.bottom+",宽="+(ellip.right-ellip.left)+",高"+(ellip.bottom-ellip.top));
									invalidate();
								}else if(partPressed==5){
									int deltax=ix-pxSaved.x;
									int deltay=iy-pxSaved.y;
									ellip.left=ellipSaved.left+deltax;
									ellip.top=ellipSaved.top+deltay;
									ellip.right=ellipSaved.right+deltax;
									ellip.bottom=ellipSaved.bottom+deltay;
									imp.status.setText("左="+ellip.left+",上="+ellip.top+",右="+ellip.right+",下="+ellip.bottom+",宽="+(ellip.right-ellip.left)+",高"+(ellip.bottom-ellip.top));
									invalidate();
								}else{
									atFingerScrolling(dx,dy);
								}
							}else if(imp.ivNow==imp.ivPick){
								invalidate();
							}else{
								if(imp.ivNow==imp.ivDrag||imp.ivNow!=null){
									atFingerScrolling(dx,dy);
								}else{
									Point point=calculClicked(ex+sx,ey+sy);
									if(point!=null){
										crosswire=new Point();
										crosswire.x=point.x;
										crosswire.y=point.y;
										imp.status.setText("x="+point.x+",y="+point.y);
										invalidate();
									}
								}
							}
						}
					}else{
						int dx_abs=Math.abs(dx);
						int dy_abs=Math.abs(dy);
						if(dx_abs>fingerMovedLimit){
							fingerMoved=true;
							moveOrientation=0;
							if(wlc!=null)wlc.interrupt();
						}else if(dy_abs>fingerMovedLimit){
							fingerMoved=true;
							moveOrientation=1;
							if(wlc!=null)wlc.interrupt();
						}
					}
				}else if(event.getPointerCount()>1){
					int a=(int)Math.abs(event.getX(0)-event.getX(1));
					int b=(int)Math.abs(event.getY(0)-event.getY(1));
					float rate=(float)Math.sqrt(a*a+b*b)/distanceSaved;
					int imageWWill=(int)(imageWSaved*rate);
					scaled=true;
					if(wlc!=null)wlc.interrupt();
					if(imageWWill<=imageWMax){
						if(imageWWill>=imageWMin){
							imageW=imageWWill;
						}else{
							imageW=imageWMin;
						}
					}else{
						imageW=imageWMax;
					}
					float scaleNow=(float)imageW/iw;
					rate=(float)imageW/imageWSaved;
					//float scaleOld=(float)imageWSaved/iw;
					int xoffs=(scaleCenterX+scrollXSaved);//*imageWSaved/iw;
					int yoffs=(scaleCenterY+scrollYSaved);//*imageWSaved/iw;
					//int scrollXWill=scrollXSaved+(int)(xoffs*scaleNow-xoffs);
					//int scrollYWill=scrollYSaved+(int)(yoffs*scaleNow-yoffs);
					atFingerScrolling(-(int)(xoffs*rate-xoffs),-(int)(yoffs*rate-yoffs));
					//scrollTo(-scrollXWill,-scrollYWill);
					imp.status.setText("scale:"+String.format("%.1f",scaleNow));
					invalidate();
				}
				break;
			case MotionEvent.ACTION_UP:
				fingerPressed=false;
				if(longClicked){

				}else if(fingerMoved){//form the click event

				}else{
					if(!scaled){
						if(wlc!=null)wlc.interrupt();
						int actionx,actiony;
						Point point;
						if(imp.ivMouse.isSelected()){
							actionx=cursorX+getScrollX();
							actiony=cursorY+getScrollY();
							point=calculClicked(actionx,actiony);
							if(point!=null){
								atImageClicked(point);
							}
						}else{
							actionx=ex+getScrollX();
							actiony=ey+getScrollY();
							point=calculClicked(actionx,actiony);
							if(point!=null){
								atImageClicked(point);
							}
						}
					}
				}
				break;
			case MotionEvent.ACTION_CANCEL:
				fingerPressed=false;
				if(wlc!=null)wlc.interrupt();
				break;
		}
		return true;
	}
	void atFingerScrolling(int dx,int dy){
		int scrollXWill=scrollXSaved-dx;
		int scrollYWill=scrollYSaved-dy;
		int vw=getWidth();
		int vh=getHeight();
		if(scrollXWill<-vw){
			if(scrollYWill>scrollYMax){
				scrollTo(-vw,scrollYMax);

			}else if(scrollYWill<-vh){
				scrollTo(-vw,-vh);
			}else{
				scrollTo(-vw,scrollYWill);
			}
		}else if(scrollYWill<-vh){
			if(scrollXWill>scrollXMax){
				scrollTo(scrollXMax,-vh);
			}else scrollTo(scrollXWill,-vh);
		}else if(scrollXWill>scrollXMax){
			if(scrollYWill>scrollYMax){
				scrollTo(scrollXMax,scrollYMax);
			}else scrollTo(scrollXMax,scrollYWill);
		}else if(scrollYWill>scrollYMax){
			scrollTo(scrollXWill,scrollYMax);
		}else{
			scrollTo(scrollXWill,scrollYWill);
		}
	}
	void atImageClicked(Point point){
		crosswire=new Point();
		crosswire.x=point.x;
		crosswire.y=point.y;
		View ivNow=imp.ivNow;
		if(ivNow==null||ivNow==imp.ivDrag){
			imp.status.setText("x="+point.x+",y="+point.y);
			invalidate();
		}else if(ivNow==imp.ivMagic){
			iw=image.getWidth();
			ih=image.getHeight();
			int seed=image.getPixel(point.x,point.y);
			seeda=(seed&0xff000000)>>>24;
			seedr=(seed&0xff0000)>>>16;
			seedg=(seed&0xff00)>>>8;
			seedb=seed&0xff;
			View setNow=imp.setNow;
			class Timeout extends Thread{
				Timeout(){
					timeout=false;
				}
				public void run(){
					try{
						sleep(1000);
						timeout=true;
						log.alert("timeout");
					}catch(InterruptedException e){}
					//throw new TimeoutException();
				}
			}
			if(setNow==null){

				if(selected==null){
					selected=new byte[iw*ih];
					SelectionFrame sf=new SelectionFrame();
					imp.undoable.push(sf);
					imp.redoable.clear();
				}else{
					SelectionFrame sf=new SelectionFrame(selected);
					imp.undoable.push(sf);
					imp.redoable.clear();
					selected=new byte[iw*ih];
				}
				ma.gui.ivUndo.setColorFilter(null);
				ma.gui.ivUndo.invalidate();
				ma.gui.ivRedo.setColorFilter(IconView.unable);
				ma.gui.ivRedo.invalidate();
				growed=new boolean[iw][ih];
				Canvas canvas=new Canvas(imageMask);
				canvas.drawColor(0,PorterDuff.Mode.SRC);
				pixelGrowed=0;
				timeout=false;
				Timeout t=new Timeout();
				t.start();
				if(growAngle){
					grow(point.x,point.y);
				}else{
					growNear(image,selected,deviation,point.x,point.y);
				}
				t.interrupt();
				invalidate();
			}else if(setNow==imp.setAll){
				growed=new boolean[iw][ih];

				pixelGrowed=0;
				Timeout t=new Timeout();
				if(selected==null){
					selected=new byte[iw*ih];
					SelectionFrame sf=new SelectionFrame(selected);
					imp.undoable.push(sf);

				}else{
					SelectionFrame sf=new SelectionFrame(selected);
					imp.undoable.push(sf);
				}
				ma.gui.ivUndo.setColorFilter(null);
				ma.gui.ivUndo.invalidate();
				imp.redoable.clear();
				ma.gui.ivRedo.setColorFilter(IconView.unable);
				ma.gui.ivRedo.invalidate();
				t.start();
				try{
					if(growAngle){
						grow(point.x,point.y);
					}else{
						growNear(image,selected,deviation,point.x,point.y);
					}
					t.interrupt();
				}catch(Exception e){
					log.alert(e.toString());
				}
				invalidate();
			}else if(setNow==imp.setXor){
				growed=new boolean[iw][ih];
				pixelGrowed=0;
				Timeout t=new Timeout();
				if(selected==null){
					selected=new byte[iw*ih];
					SelectionFrame sf=new SelectionFrame();
					imp.undoable.push(sf);

				}else{
					SelectionFrame sf=new SelectionFrame();
					imp.undoable.push(sf);
				}
				ma.gui.ivUndo.setColorFilter(null);
				ma.gui.ivUndo.invalidate();
				imp.redoable.clear();
				ma.gui.ivRedo.setColorFilter(IconView.unable);
				ma.gui.ivRedo.invalidate();
				//selectedSaved=selected;
				//selected=new byte[iw][ih];
				t.start();
				try{
					if(growAngle){
						growXor(point.x,point.y);
					}else{
						growNearXor(point.x,point.y);
					}
					t.interrupt();
				}catch(TimeoutException e){
					log.alert(e.toString());
				}
				invalidate();
			}else if(setNow==imp.setLeft){
				growed=new boolean[iw][ih];
				pixelGrowed=0;
				Timeout t=new Timeout();
				if(selected==null){
					selected=new byte[iw*ih];
					SelectionFrame sf=new SelectionFrame();
					imp.undoable.push(sf);
				}else{
					SelectionFrame sf=new SelectionFrame(selected);
					imp.undoable.push(sf);
				}
				ma.gui.ivUndo.setColorFilter(null);
				ma.gui.ivUndo.invalidate();
				imp.redoable.clear();
				ma.gui.ivRedo.setColorFilter(IconView.unable);
				ma.gui.ivRedo.invalidate();
				t.start();
				try{
					if(growAngle){
						growLeft(point.x,point.y);
					}else{
						growNearLeft(point.x,point.y);
					}
					t.interrupt();
				}catch(TimeoutException e){
					log.alert(e.toString());
				}
				invalidate();
			}else if(setNow==imp.setCenter){
				growed=new boolean[iw][ih];
				pixelGrowed=0;
				Timeout t=new Timeout();
				if(selected==null){
					selected=new byte[iw*ih];
					SelectionFrame sf=new SelectionFrame();
					imp.undoable.push(sf);
					ma.gui.ivUndo.setColorFilter(null);
					ma.gui.ivUndo.invalidate();
					imp.redoable.clear();
					ma.gui.ivUndo.setColorFilter(IconView.unable);
					ma.gui.ivUndo.invalidate();
				}else{
					SelectionFrame sf=new SelectionFrame(selected);
					imp.undoable.push(sf);
					ma.gui.ivUndo.setColorFilter(null);
					ma.gui.ivUndo.invalidate();
					imp.redoable.clear();
					ma.gui.ivUndo.setColorFilter(IconView.unable);
					ma.gui.ivUndo.invalidate();
				}
				t.start();
				selectedSaved=selected;
				selected=new byte[iw*ih];
				try{
					if(growAngle){
						growCenter(point.x,point.y);
					}else{
						growNearCenter(point.x,point.y);
					}
					t.interrupt();
					imp.makeMask(selected);
					invalidate();
				}catch(TimeoutException e){
					log.alert(e.toString());
				}
			}else if(setNow==imp.setRight){
				growed=new boolean[iw][ih];
				pixelGrowed=0;
				Timeout t=new Timeout();
				if(selected==null){
					selected=new byte[iw*ih];
					SelectionFrame sf=new SelectionFrame();
					imp.undoable.push(sf);
				}else{
					SelectionFrame sf=new SelectionFrame(selected);
					imp.undoable.push(sf);
				}
				ma.gui.ivUndo.setColorFilter(null);
				ma.gui.ivUndo.invalidate();
				imp.redoable.clear();
				ma.gui.ivRedo.setColorFilter(IconView.unable);
				ma.gui.ivRedo.invalidate();
				t.start();
				selectedSaved=selected;
				selected=new byte[iw*ih];
				try{
					if(growAngle){
						growRight(point.x,point.y);
					}else{
						growNearRight(point.x,point.y);
					}
					t.interrupt();
					imp.makeMask(selected);
					invalidate();
				}catch(Exception e){
					log.alert(e.toString());
				}
			}

			invalidate();
			imp.status.setText(pixelGrowed+"个像素被选中");
		}else if(imp.ivNow==imp.ivTubular){
			int px=image.getPixel(point.x,point.y);
			imp.foregroundColor=px;
			imp.status.setText("拾取颜色："+String.format("#%08x",px));
			imp.colorReveal.invalidate();
			invalidate();
		}else{
			invalidate();
		}
	}
	int selectionMask=0xff000000;
	int seeda,seedr,seedg,seedb;
	int pixelGrowed;
	int gl,gt,gr,gb;
	boolean[][] growed;
	byte[] selectedSaved;
	int iw,ih;
	volatile boolean timeout;
	void growNearRight(int x,int y)throws TimeoutException{
		if(growed[x][y])return;
		if(timeout)throw new TimeoutException("timeout at grow pixel");
		int px=image.getPixel(x,y);
		if(pixcmp(px)){
			growed[x][y]=true;
			int v=(0|selectedSaved[x*y])>>>24;
			selected[x*y]=(byte)(255-v);
			pixelGrowed++;
		}else return;
		if(x-1>=0){
			growNearRight(x-1,y);
			if(y-1>=0){
				growNearRight(x,y-1);
				if(x+1<iw){
					growNearRight(x+1,y);
					if(y+1<ih){
						growNearRight(x,y+1);
					}
				}else if(y+1<ih){
					growNearRight(x,y+1);
				}
			}else if(x+1<iw){
				growNearRight(x+1,y);
				if(y+1<ih){
					growNearRight(x,y+1);
				}
			}else if(y+1<ih){
				growNearRight(x,y+1);
			}
		}else if(y-1>=0){
			growNearRight(x,y-1);
			if(x+1<iw){
				growNearRight(x+1,y);
				if(y+1<ih){
					growNearRight(x,y+1);
				}
			}else if(y+1<ih){
				growNearRight(x,y+1);
			}
		}else if(x+1<iw){
			growNearRight(x+1,y);
			if(y+1<ih){
				growNearRight(x,y+1);
			}
		}else if(y+1<ih){
			growNearRight(x,y+1);
		}
	}
	boolean pixcmp(int i){return true;}
	void growRight(int x,int y)throws TimeoutException{
		if(growed[x][y])return;
		if(timeout)throw new TimeoutException("timeout at grow pixel");
		int px=image.getPixel(x,y);
		if(pixcmp(px)){
			growed[x][y]=true;
			int v=(0|selectedSaved[x+iw*y])>>>24;
			selected[x+iw*y]=(byte)(255-v);
			pixelGrowed++;
		}else return;
		if(x-1>=0){
			growRight(x-1,y);
			if(y-1>=0){
				growRight(x-1,y-1);
				growRight(x,y-1);
				if(x+1<iw){
					growRight(x+1,y);
					growRight(x+1,y-1);
					if(y+1<ih){
						growRight(x+1,y+1);
						growRight(x,y+1);
						growRight(x-1,y+1);
					}
				}
			}else if(x+1<iw){
				growRight(x+1,y);
				if(y+1<ih){
					growRight(x-1,y+1);
					growRight(x,y+1);
					growRight(x+1,y+1);
				}
			}else if(y+1<ih){
				growRight(y+1,x-1);
				growRight(y+1,x);
			}
		}else if(y-1>=0){
			growRight(x,y-1);
			if(x+1<iw){
				growRight(x+1,y);
				growRight(x+1,y-1);
				if(y+1<ih){
					growRight(x,y+1);
					growRight(x+1,y+1);
				}
			}else if(y+1<ih){
				growRight(x,y+1);
			}
		}else if(x+1<iw){
			growRight(x+1,y);
			if(y+1<ih){
				growRight(x+1,y+1);
				growRight(x,y+1);
			}
		}else if(y+1<ih){
			growRight(x,y+1);
		}
	}
	void growNearCenter(int x,int y)throws TimeoutException{
		if(growed[x][y])return;
		if(timeout)throw new TimeoutException("timeout at grow pixel");
		int px=image.getPixel(x,y);
		if(pixcmp(px)){
			growed[x][y]=true;
			selected[x+iw*y]=selectedSaved[x+iw*y];
			pixelGrowed++;
		}else return;
		if(x-1>=0){
			growNearCenter(x-1,y);
			if(y-1>=0){
				growNearCenter(x,y-1);
				if(x+1<iw){
					growNearCenter(x+1,y);
					if(y+1<ih){
						growNearCenter(x,y+1);
					}
				}else if(y+1<ih){
					growNearCenter(x,y+1);
				}
			}else if(x+1<iw){
				growNearCenter(x+1,y);
				if(y+1<ih){
					growNearCenter(x,y+1);
				}
			}else if(y+1<ih){
				growNearCenter(x,y+1);
			}
		}else if(y-1>=0){
			growNearCenter(x,y-1);
			if(x+1<iw){
				growNearCenter(x+1,y);
				if(y+1<ih){
					growNearCenter(x,y+1);
				}
			}else if(y+1<ih){
				growNearCenter(x,y+1);
			}
		}else if(x+1<iw){
			growNearCenter(x+1,y);
			if(y+1<ih){
				growNearCenter(x,y+1);
			}
		}else if(y+1<ih){
			growNearCenter(x,y+1);
		}
	}
	void growCenter(int x,int y)throws TimeoutException{
		if(growed[x][y])return;
		if(timeout)throw new TimeoutException("timeout at grow pixel");
		int px=image.getPixel(x,y);
		if(pixcmp(px)){
			growed[x][y]=true;
			selected[x+iw*y]=selectedSaved[x+iw*y];
			pixelGrowed++;
		}else return;
		if(x-1>=0){
			growCenter(x-1,y);
			if(y-1>=0){
				growCenter(x-1,y-1);
				growCenter(x,y-1);
				if(x+1<iw){
					growCenter(x+1,y);
					growCenter(x+1,y-1);
					if(y+1<ih){
						growCenter(x+1,y+1);
						growCenter(x,y+1);
						growCenter(x-1,y+1);
					}
				}
			}else if(x+1<iw){
				growCenter(x+1,y);
				if(y+1<ih){
					growCenter(x-1,y+1);
					growCenter(x,y+1);
					growCenter(x+1,y+1);
				}
			}else if(y+1<ih){
				growCenter(y+1,x-1);
				growCenter(y+1,x);
			}
		}else if(y-1>=0){
			growCenter(x,y-1);
			if(x+1<iw){
				growCenter(x+1,y);
				growCenter(x+1,y-1);
				if(y+1<ih){
					growCenter(x,y+1);
					growCenter(x+1,y+1);
				}
			}else if(y+1<ih){
				growCenter(x,y+1);
			}
		}else if(x+1<iw){
			growCenter(x+1,y);
			if(y+1<ih){
				growCenter(x+1,y+1);
				growCenter(x,y+1);
			}
		}else if(y+1<ih){
			growCenter(x,y+1);
		}
	}
	void growNearLeft(int x,int y)throws TimeoutException{
		if(growed[x][y])return;
		if(timeout)throw new TimeoutException("at grow pixel");
		int px=image.getPixel(x,y);
		if(pixcmp(px)){
			growed[x][y]=true;
			selected[x+iw*y]=0;
			pixelGrowed++;
			imageMask.setPixel(x,y,0);
		}else return;
		if(x-1>=0){
			growNearLeft(x-1,y);
			if(y-1>=0){
				growNearLeft(x,y-1);
				if(x+1<iw){
					growNearLeft(x+1,y);
					if(y+1<ih){
						growNearLeft(x,y+1);
					}
				}else if(y+1<ih){
					growNearLeft(x,y+1);
				}
			}else if(x+1<iw){
				growNearLeft(x+1,y);
				if(y+1<ih){
					growNearLeft(x,y+1);
				}
			}else if(y+1<ih){
				growNearLeft(x,y+1);
			}
		}else if(y-1>=0){
			growNearLeft(x,y-1);
			if(x+1<iw){
				growNearLeft(x+1,y);
				if(y+1<ih){
					growNearLeft(x,y+1);
				}
			}else if(y+1<ih){
				growNearLeft(x,y+1);
			}
		}else if(x+1<iw){
			growNearLeft(x+1,y);
			if(y+1<ih){
				growNearLeft(x,y+1);
			}
		}else if(y+1<ih){
			growNearLeft(x,y+1);
		}
	}
	void growLeft(int x,int y)throws TimeoutException{
		if(growed[x][y])return;
		if(timeout)throw new TimeoutException("进行xor选择时工作超时");
		int px=image.getPixel(x,y);
		if(pixcmp(px)){
			growed[x][y]=true;
			selected[x+iw*y]=0;
			pixelGrowed++;
			imageMask.setPixel(x,y,0);
		}else return;
		if(x-1>=0){
			growLeft(x-1,y);
			if(y-1>=0){
				growLeft(x-1,y-1);
				growLeft(x,y-1);
				if(x+1<iw){
					growLeft(x+1,y);
					growLeft(x+1,y-1);
					if(y+1<ih){
						growLeft(x+1,y+1);
						growLeft(x,y+1);
						growLeft(x-1,y+1);
					}
				}
			}else if(x+1<iw){
				growLeft(x+1,y);
				if(y+1<ih){
					growLeft(x-1,y+1);
					growLeft(x,y+1);
					growLeft(x+1,y+1);
				}
			}else if(y+1<ih){
				growLeft(y+1,x-1);
				growLeft(y+1,x);
			}
		}else if(y-1>=0){
			growLeft(x,y-1);
			if(x+1<iw){
				growLeft(x+1,y);
				growLeft(x+1,y-1);
				if(y+1<ih){
					growLeft(x,y+1);
					growLeft(x+1,y+1);
				}
			}else if(y+1<ih){
				growLeft(x,y+1);
			}
		}else if(x+1<iw){
			growLeft(x+1,y);
			if(y+1<ih){
				growLeft(x+1,y+1);
				growLeft(x,y+1);
			}
		}else if(y+1<ih){
			growLeft(x,y+1);
		}
	}
	void growXor(int x,int y)throws TimeoutException{
		if(growed[x][y])return;
		if(timeout)throw new TimeoutException("进行xor选择时工作超时");
		int px=image.getPixel(x,y);
		if(pixcmp(px)){
			growed[x][y]=true;
			int v=(0|selected[x+iw*y])>>>24;
			int out=255-v;
			selected[x+iw*y]=(byte)(out);
			pixelGrowed++;
			imageMask.setPixel(x,y,selectionMask);
		}else return;
		if(x-1>=0){
			growXor(x-1,y);
			if(y-1>=0){
				growXor(x-1,y-1);
				growXor(x,y-1);
				if(x+1<iw){
					growXor(x+1,y);
					growXor(x+1,y-1);
					if(y+1<ih){
						growXor(x+1,y+1);
						growXor(x,y+1);
						growXor(x-1,y+1);
					}
				}
			}else if(x+1<iw){
				growXor(x+1,y);
				if(y+1<ih){
					growXor(x-1,y+1);
					growXor(x,y+1);
					growXor(x+1,y+1);
				}
			}else if(y+1<ih){
				growXor(y+1,x-1);
				growXor(y+1,x);
			}
		}else if(y-1>=0){
			growXor(x,y-1);
			if(x+1<iw){
				growXor(x+1,y);
				growXor(x+1,y-1);
				if(y+1<ih){
					growXor(x,y+1);
					growXor(x+1,y+1);
				}
			}else if(y+1<ih){
				growXor(x,y+1);
			}
		}else if(x+1<iw){
			growXor(x+1,y);
			if(y+1<ih){
				growXor(x+1,y+1);
				growXor(x,y+1);
			}
		}else if(y+1<ih){
			growXor(x,y+1);
		}
	}
	void growNearXor(int x,int y)throws TimeoutException{
		if(growed[x][y])return;
		if(timeout)throw new TimeoutException("进行xor选择生长像素时");
		int px=image.getPixel(x,y);
		if(pixcmp(px)){
			growed[x][y]=true;
			int v=(0|selected[x+iw*y])>>>24;
			int out=255-v;
			out=Math.max(out,255);
			selected[x+iw*y]=(byte)(out);
			pixelGrowed++;
			imageMask.setPixel(x,y,selectionMask);
		}else return;
		if(x-1>=0){
			growNearXor(x-1,y);
			if(y-1>=0){
				growNearXor(x,y-1);
				if(x+1<iw){
					growNearXor(x+1,y);
					if(y+1<ih){
						growNearXor(x,y+1);
					}
				}else if(y+1<ih){
					growNearXor(x,y+1);
				}
			}else if(x+1<iw){
				growNearXor(x+1,y);
				if(y+1<ih){
					growNearXor(x,y+1);
				}
			}else if(y+1<ih){
				growNearXor(x,y+1);
			}
		}else if(y-1>=0){
			growNearXor(x,y-1);
			if(x+1<iw){
				growNearXor(x+1,y);
				if(y+1<ih){
					growNearXor(x,y+1);
				}
			}else if(y+1<ih){
				growNearXor(x,y+1);
			}
		}else if(x+1<iw){
			growNearXor(x+1,y);
			if(y+1<ih){
				growNearXor(x,y+1);
			}
		}else if(y+1<ih){
			growNearXor(x,y+1);
		}
	}
	String error;
	void grow(int x,int y){
		if(growed[x][y])return;
		if(timeout){
			return;
		}
		int px=image.getPixel(x,y);
		if(pixcmp(px)){
			growed[x][y]=true;
			selected[x+iw*y]=-1;
			pixelGrowed++;
			imageMask.setPixel(x,y,selectionMask);
		}else return;
		if(x-1>=0){
			grow(x-1,y);
			if(y-1>=0){
				grow(x-1,y-1);
				grow(x,y-1);
				if(x+1<iw){
					grow(x+1,y);
					grow(x+1,y-1);
					if(y+1<ih){
						grow(x+1,y+1);
						grow(x,y+1);
						grow(x-1,y+1);
					}
				}
			}else if(x+1<iw){
				grow(x+1,y);
				if(y+1<ih){
					grow(x-1,y+1);
					grow(x,y+1);
					grow(x+1,y+1);
				}
			}else if(y+1<ih){
				grow(y+1,x-1);
				grow(y+1,x);
			}
		}else if(y-1>=0){
			grow(x,y-1);
			if(x+1<iw){
				grow(x+1,y);
				grow(x+1,y-1);
				if(y+1<ih){
					grow(x,y+1);
					grow(x+1,y+1);
				}
			}else if(y+1<ih){
				grow(x,y+1);
			}
		}else if(x+1<iw){
			grow(x+1,y);
			if(y+1<ih){
				grow(x+1,y+1);
				grow(x,y+1);
			}
		}else if(y+1<ih){
			grow(x,y+1);
		}
	}
	native void growNear(Bitmap bm,byte[] channel,int deviation,int x,int y);
	void growNear_(int x,int y){
		int[] xlocs=new int[iw*ih];
		int[] ylocs=new int[iw*ih];
		int top=0;
		xlocs[top]=x;
		ylocs[top]=y;
		try{
		do{
			x=xlocs[top];
			y=ylocs[top];
			int px=image.getPixel(x,y);
			growed[x][y]=true;
			top--;
			if(pixcmp(px)){
				selected[x+iw*y]=-1;
				pixelGrowed++;
				imageMask.setPixel(x,y,selectionMask);
				if(x-1>=0){
					if(!growed[x-1][y]){top++;xlocs[top]=x-1;ylocs[top]=y;}
					if(y-1>=0){
						if(!growed[x][y-1]){top++;xlocs[top]=x;ylocs[top]=y-1;}
						if(x+1<iw){
							if(!growed[x+1][y]){top++;xlocs[top]=x+1;ylocs[top]=y;}
							if(y+1<ih){
								if(!growed[x][y+1]){top++;xlocs[top]=x;ylocs[top]=y+1;}
							}
						}else if(y+1<ih){
							if(!growed[x][y+1]){top++;xlocs[top]=x;ylocs[top]=y+1;}
						}
					}else if(x+1<iw){
						if(!growed[x+1][y]){top++;xlocs[top]=x+1;ylocs[top]=y;}
						if(y+1<ih){
							if(!growed[x][y+1]){top++;xlocs[top]=x;ylocs[top]=y+1;}
						}
					}else if(y+1<ih){
						if(!growed[x][y+1]){top++;xlocs[top]=x;ylocs[top]=y+1;}
					}
				}else if(y-1>=0){
					if(!growed[x][y-1]){top++;xlocs[top]=x;ylocs[top]=y-1;}
					if(x+1<iw){
						if(!growed[x+1][y]){top++;xlocs[top]=x+1;ylocs[top]=y;}
						if(y+1<ih){
							if(!growed[x][y+1]){top++;xlocs[top]=x;ylocs[top]=y+1;}
						}
					}else if(y+1<ih){
						if(!growed[x][y+1]){top++;xlocs[top]=x;ylocs[top]=y+1;}
					}
				}else if(x+1<iw){
					if(!growed[x+1][y]){top++;xlocs[top]=x+1;ylocs[top]=y;}
					if(y+1<ih){
						if(!growed[x][y+1]){top++;xlocs[top]=x;ylocs[top]=y+1;}
					}
				}else if(y+1<ih){
					if(!growed[x][y+1]){top++;xlocs[top]=x;ylocs[top]=y+1;}
				}
			}
		}while(top>=0);
		}catch(Exception e){log.alert(e.toString());}
		/*if(x-1>=0){
			growNear(x-1,y);
			if(y-1>=0){
				growNear(x,y-1);
				if(x+1<iw){
					growNear(x+1,y);
					if(y+1<ih){
						growNear(x,y+1);
					}
				}else if(y+1<ih){
					growNear(x,y+1);
				}
			}else if(x+1<iw){
				growNear(x+1,y);
				if(y+1<ih){
					growNear(x,y+1);
				}
			}else if(y+1<ih){
				growNear(x,y+1);
			}
		}else if(y-1>=0){
			growNear(x,y-1);
			if(x+1<iw){
				growNear(x+1,y);
				if(y+1<ih){
					growNear(x,y+1);
				}
			}else if(y+1<ih){
				growNear(x,y+1);
			}
		}else if(x+1<iw){
			growNear(x+1,y);
			if(y+1<ih){
				growNear(x,y+1);
			}
		}else if(y+1<ih){
			growNear(x,y+1);
		}*/
	}
	Point calculClicked(int actionx,int actiony){
		int iw=image.getWidth();
		int ih=image.getHeight();
		int imageH=ih*imageW/iw;
		int pixelX=iw*actionx/imageW;
		int pixelY=ih*actiony/imageH;
		if(pixelX>=0&&pixelY>=0){
			if(pixelX<iw){
				if(pixelY<ih){
					return new Point(pixelX,pixelY);
				}else if(pixelY==ih){
					return new Point(pixelX,ih-1);
				}
			}else if(pixelX==iw){
				if(pixelY<ih){
					return new Point(iw-1,pixelY);
				}else if(pixelY==ih){
					return new Point(iw-1,ih-1);
				}
			}
		}
		return null;
	}
	int cursorWidth;
	int cursorHeight;
	int cursorX;
	int cursorY;
	int handleRadius;
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		cursorWidth=(int)(20*ma.dp);
		cursorHeight=(int)(16*ma.dp);
		handleRadius=(int)(10*ma.dp);
		int vw=getMeasuredWidth();
		int vh=getMeasuredHeight();
		cursorX=vw/2;
		cursorY=vh/2;
		scrollYMin=-vw;
		scrollXMin=-vh;
		velocity=0.1f*ma.dp;
	}
	float velocity;
	@Override
	protected void onVisibilityChanged(View changedView, int visibility) {
		super.onVisibilityChanged(changedView, visibility);
		if(visibility!=VISIBLE){

		}
	}

	@Override
	protected void onDraw(Canvas canvas) {
		int zebraWidth=(int)(8*ma.dp);
		int vw=getWidth();
		int vh=getHeight();
		int iw=image.getWidth();
		int ih=image.getHeight();
		int sx=getScrollX();
		int sy=getScrollY();
		float scale=imageW/(float)iw;
		int imageBottom=(int)(ih*scale);
		canvas.save();
		scrollXMax=imageW;
		scrollYMax=imageBottom;
		canvas.clipRect(0,0,imageW,imageBottom);
		canvas.drawColor(0xffdddddd);
		Paint p=new Paint();
		p.setColor(0x7f999999);
		for(int x=sx%(zebraWidth*2);x<imageW;x+=zebraWidth*2){
			canvas.drawRect(x,0,x+zebraWidth,imageBottom,p);
		}
		for(int y=sy%(zebraWidth*2);y<imageBottom;y+=zebraWidth*2){
			canvas.drawRect(0,y,imageW,y+zebraWidth,p);
		}
		Rect imageRect=new Rect(0,0,imageW,imageBottom);
		canvas.drawBitmap(image,null,imageRect,bitmapPaint);
		if(!imp.editMode){
			if(imageMask!=null){
				int id=canvas.saveLayer(null,null);
				canvas.drawBitmap(imageMask,null,imageRect,bitmapPaint);
				bitmapPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
				LinearGradient selectionShader;
				float offs=(int)(System.currentTimeMillis()&0xffffffffl)*velocity;
				int shaderLen=(int)Math.sqrt(vw*vw+vh*vh);
				int ff=(int)(offs%shaderLen);
				int xxx=vw*ff/shaderLen;
				int yyy=vh*ff/shaderLen;
				selectionShader=new LinearGradient(sx+xxx,sy+yyy,vw+sx+xxx,vh+sy+yyy,new int[]{Color.RED,Color.GREEN,Color.BLUE,Color.RED,Color.GREEN,Color.BLUE},null,Shader.TileMode.REPEAT);
				bitmapPaint.setShader(selectionShader);
				canvas.drawRect(sx,sy,sx+vw,sy+vh,bitmapPaint);
				canvas.restoreToCount(id);
				bitmapPaint.setShader(null);
				bitmapPaint.setXfermode(null);
				invalidate();
			}
		}

		canvas.restore();
		int colorOut=0xff7f7f7f;
		int border=5;
		int out=2;
		int indicStroke=1;
		DashPathEffect dpe=new DashPathEffect(new float[]{5,5},0);
		DashPathEffect dp2=new DashPathEffect(new float[]{5,5},5);
		if(rectSelection!=null){
			int gl=(int)(rectSelection.left*scale);
			int gt=(int)(rectSelection.top*scale);
			int gr=(int)(rectSelection.right*scale);
			int gb=(int)(rectSelection.bottom*scale);
			Path indic=new Path();
			indic.addRect(gl,gt,gr,gb,Path.Direction.CW);
			p.setStrokeWidth(indicStroke);
			p.setColor(0xff000000);
			p.setPathEffect(dpe);
			p.setStyle(Paint.Style.STROKE);
			canvas.drawPath(indic,p);
			p.setColor(0xffffffff);
			p.setPathEffect(dp2);
			canvas.drawPath(indic,p);
			p.setPathEffect(null);
			p.setStyle(Paint.Style.FILL);
			if(imp.ivNow==imp.ivRectSelect){
				p.setColor(colorOut);
				int ll=gl-handleRadius;
				int tt=gt-handleRadius;
				int rr=gl+handleRadius;
				int bb=gt+handleRadius;
				canvas.drawRect(ll,tt,ll+out,bb,p);
				canvas.drawRect(ll,tt,rr,tt+out,p);
				canvas.drawRect(rr-out,tt,rr,bb,p);
				canvas.drawRect(ll,bb-out,rr,bb,p);
				p.setColor(0xffffffff);
				canvas.drawRect(ll+out,tt+out,ll+border,bb-out,p);
				canvas.drawRect(ll+out,tt+out,rr-out,tt+border,p);
				canvas.drawRect(rr-border,tt+out,rr-out,bb-out,p);
				canvas.drawRect(ll+out,bb-border,rr-out,bb-out,p);
				ll=gr-handleRadius;
				tt=gb-handleRadius;
				rr=gr+handleRadius;
				bb=gb+handleRadius;
				p.setColor(colorOut);
				canvas.drawRect(ll,tt,ll+out,bb,p);
				canvas.drawRect(ll,tt,rr,tt+out,p);
				canvas.drawRect(rr-out,tt,rr,bb,p);
				canvas.drawRect(ll,bb-out,rr,bb,p);
				p.setColor(0xffffffff);
				canvas.drawRect(ll+out,tt+out,ll+border,bb-out,p);
				canvas.drawRect(ll+out,tt+out,rr-out,tt+border,p);
				canvas.drawRect(rr-border,tt+out,rr-out,bb-out,p);
				canvas.drawRect(ll+out,bb-border,rr-out,bb-out,p);
				int cx=(gr-gl)/2+gl;
				int cy=(gb-gt)/2+gt;
				ll=cx-handleRadius;
				tt=cy-handleRadius;
				rr=cx+handleRadius;
				bb=cy+handleRadius;
				p.setColor(0xff000000);
				canvas.drawRect(ll,tt,ll+out,bb,p);
				canvas.drawRect(ll,tt,rr,tt+out,p);
				canvas.drawRect(rr-out,tt,rr,bb,p);
				canvas.drawRect(ll,bb-out,rr,bb,p);
				p.setColor(0xffffffff);
				canvas.drawRect(ll+out,tt+out,ll+border,bb-out,p);
				canvas.drawRect(ll+out,tt+out,rr-out,tt+border,p);
				canvas.drawRect(rr-border,tt+out,rr-out,bb-out,p);
				canvas.drawRect(ll+out,bb-border,rr-out,bb-out,p);
				p.setStyle(Paint.Style.STROKE);
				p.setStrokeWidth(handleRadius/5);
				canvas.drawLine(ll+out,cy,rr-out,cy,p);
				canvas.drawLine(cx,tt+out,cx,bb-out,p);
			}

		}
		if(ellip!=null){
			int gl=(int)(ellip.left*scale);
			int gt=(int)(ellip.top*scale);
			int gr=(int)(ellip.right*scale);
			int gb=(int)(ellip.bottom*scale);
			Path indic=new Path();
			indic.addOval(gl,gt,gr,gb,Path.Direction.CW);
			p.setStrokeWidth(indicStroke);
			p.setColor(0xff000000);
			p.setPathEffect(dpe);
			p.setStyle(Paint.Style.STROKE);
			canvas.drawPath(indic,p);
			p.setColor(0xffffffff);
			p.setPathEffect(dp2);
			canvas.drawPath(indic,p);
			p.setPathEffect(null);
			p.setStyle(Paint.Style.FILL);
			if(imp.ivNow==imp.ivEllipseSelect){
				p.setColor(colorOut);
				int ll=gl-handleRadius;
				int tt=gt-handleRadius;
				int rr=gl+handleRadius;
				int bb=gt+handleRadius;
				canvas.drawRect(ll,tt,ll+out,bb,p);
				canvas.drawRect(ll,tt,rr,tt+out,p);
				canvas.drawRect(rr-out,tt,rr,bb,p);
				canvas.drawRect(ll,bb-out,rr,bb,p);
				p.setColor(0xffffffff);
				canvas.drawRect(ll+out,tt+out,ll+border,bb-out,p);
				canvas.drawRect(ll+out,tt+out,rr-out,tt+border,p);
				canvas.drawRect(rr-border,tt+out,rr-out,bb-out,p);
				canvas.drawRect(ll+out,bb-border,rr-out,bb-out,p);
				ll=gr-handleRadius;
				tt=gb-handleRadius;
				rr=gr+handleRadius;
				bb=gb+handleRadius;
				p.setColor(colorOut);
				canvas.drawRect(ll,tt,ll+out,bb,p);
				canvas.drawRect(ll,tt,rr,tt+out,p);
				canvas.drawRect(rr-out,tt,rr,bb,p);
				canvas.drawRect(ll,bb-out,rr,bb,p);
				p.setColor(0xffffffff);
				canvas.drawRect(ll+out,tt+out,ll+border,bb-out,p);
				canvas.drawRect(ll+out,tt+out,rr-out,tt+border,p);
				canvas.drawRect(rr-border,tt+out,rr-out,bb-out,p);
				canvas.drawRect(ll+out,bb-border,rr-out,bb-out,p);
				int cx=(gr-gl)/2+gl;
				int cy=(gb-gt)/2+gt;
				ll=cx-handleRadius;
				tt=cy-handleRadius;
				rr=cx+handleRadius;
				bb=cy+handleRadius;
				p.setColor(0xff000000);
				canvas.drawRect(ll,tt,ll+out,bb,p);
				canvas.drawRect(ll,tt,rr,tt+out,p);
				canvas.drawRect(rr-out,tt,rr,bb,p);
				canvas.drawRect(ll,bb-out,rr,bb,p);
				p.setColor(0xffffffff);
				canvas.drawRect(ll+out,tt+out,ll+border,bb-out,p);
				canvas.drawRect(ll+out,tt+out,rr-out,tt+border,p);
				canvas.drawRect(rr-border,tt+out,rr-out,bb-out,p);
				canvas.drawRect(ll+out,bb-border,rr-out,bb-out,p);
				p.setStyle(Paint.Style.STROKE);
				p.setStrokeWidth(handleRadius/5);
				canvas.drawLine(ll+out,cy,rr-out,cy,p);
				canvas.drawLine(cx,tt+out,cx,bb-out,p);
			}
		}
		if(crosswire!=null){
			float xx=crosswire.x*scale;
			float yy=crosswire.y*scale;
			canvas.drawRect(xx,sy,xx+1,sy+vh,wirePaint);
			canvas.drawRect(sx,yy,sx+vw,yy+1,wirePaint);
		}
		if(imp.ivMouse.isSelected()){
			//canvas.save();
			//canvas.translate(cursorX,cursorY);
			int cursorX=this.cursorX+sx;
			int cursorY=this.cursorY+sy;
			Path path=new Path();
			path.moveTo(cursorX,cursorY);
			int tt=cursorY+cursorHeight/2;
			int bb=tt-cursorHeight;
			int rr=cursorX+cursorWidth;
			int n=cursorHeight/5;
			int pillarTop=cursorY+n;
			int pillarBottom=cursorY-n;
			int pillarLeft=cursorX+cursorWidth/2;
			path.lineTo(pillarLeft,tt);
			path.lineTo(pillarLeft,pillarTop);
			path.lineTo(rr,pillarTop);
			path.lineTo(rr,pillarBottom);
			path.lineTo(pillarLeft,pillarBottom);
			path.lineTo(pillarLeft,bb);
			path.close();
			canvas.rotate(45,cursorX,cursorY);
			canvas.drawPath(path,bitmapPaint);

		}

	}
	class QueryForLayer extends LinearLayout implements OnClickListener{
		WindowManager.LayoutParams wlp=new WindowManager.LayoutParams();
		GUI.Item itExport;
		QueryForLayer(){
			super(ma);
			setOrientation(VERTICAL);
			setBackground(new GUI.BorderDrawable());
			wlp.gravity=Gravity.TOP|Gravity.LEFT;
			wlp.flags=wlp.FLAG_LAYOUT_IN_SCREEN;
			itExport=new GUI.Item(ma);
			itExport.setOnClickListener(this);
			itExport.setText("导出图层");
			LayoutParams itlp=new LayoutParams(-1,dialogHorItemHeight);
			addView(itExport,itlp);
		}
		void show(){
			wlp.width=ma.wp/2;
			wlp.height=-2;
			ma.wm.addView(this,wlp);
		}
		@Override
		public void onClick(View view) {
		}
		Point touchDown=new Point();
		@Override
		public boolean onTouchEvent(MotionEvent event){
			int x=(int)event.getX();
			int y=(int)event.getY();
			switch(event.getAction()){
				case MotionEvent.ACTION_DOWN:
					touchDown.x=x;
					touchDown.y=y;
					break;
				case MotionEvent.ACTION_UP:
					Rect visible=new Rect();
					getGlobalVisibleRect(visible);
					int[] is=new int[2];
					getLocationOnScreen(is);
					if(touchDown.x>=visible.right||touchDown.x<visible.right||touchDown.y>=visible.bottom||touchDown.y<visible.top){
						ma.wm.removeView(this);
					}
			}
			super.onTouchEvent(event);
			return true;
		}
	}
}
